﻿using System;
using HK.Core.Common.Data;
using HK.Core.Common.Protocol;
using HK.Core.Common.Protocol.Data;
using HK.Core.GUIEx.Attribute;
using HK.Core.Serializable.Protocol.Data;
using HK.Core.Utils;
using UnityEngine;

namespace HK.Core.Serializable.Data
{
	/// <summary>
	/// 无效版本异常
	/// </summary>
	public class InvalidSAssetVersionException : Exception
	{
		public InvalidSAssetVersionException(string iMessage) : base(iMessage) {}
	}
	
	/// <summary>
	/// 接口 : 序列化资产版本
	/// <para>* 版本格式 : Max.Mid.Min.Tag</para>
	/// </summary>
	[Serializable]
	public sealed class SAssetVersion : JsonData<SAssetVersion>, ISAssetVersion
	{

#region Create

		/// <summary>
		/// 创建版本号
		/// </summary>
		/// <param name="iMin">版本号 - Min</param>
		/// <param name="iMid">版本号 - Mid</param>
		/// <param name="iMax">版本号 - Max</param>
		/// <param name="iTag">版本号 - Tag</param>
		/// <returns></returns>
		public static SAssetVersion Create(int iMin = 1, int iMid = 0, int iMax = 0, string iTag = null)
		{
			return new SAssetVersion
			{
				min = iMin, mid = iMid, max = iMax, tag = iTag
			};
		}

#endregion
		
		/// <summary>
		/// 保护构造函数
		/// </summary>
		private SAssetVersion() {}
        
		[SerializeField, IntMinMax("大", 0, 999)]
		private int max = 0;
		/// <summary>
		/// Max
		/// </summary>
		public int Max 
		{
			get => max;
			set => max = value;
		}
       
		[SerializeField, IntMinMax("中", 0, 999)]
		private int mid = 0;
		/// <summary>
		/// Mid
		/// </summary>
		public int Mid 
		{
			get => mid;
			set => mid = value;
		}

		[SerializeField, IntMinMax("小", 0, 999)]
		private int min = 1;
		/// <summary>
		/// Min
		/// </summary>
		public int Min
		{
			get => min;
			set => min = value;
		}
        
		[SerializeField, HideInInspector]
		private string tag = null;
		/// <summary>
		/// Tag
		/// </summary>
		public string Tag 
		{
			get => tag;
			set => tag = value;
		}
        
		/// <summary>
		/// 版本信息 - 短
		/// <para>* 版本格式 : Max.Mid.Min</para>
		/// </summary>
		public string Short => $"{max}.{mid}.{min}";
        
		/// <summary>
		/// 版本信息 - All
		/// <para>* 版本格式 : Max.Mid.Min.Tag</para>
		/// </summary>
		public string Full => string.IsNullOrEmpty(tag) ? $"{Short}" : $"{Short}.{tag}";

		/// <summary>
		/// 克隆自身
		/// <para>* 会生成新对象</para>
		/// </summary>
		/// <returns>克隆后的版本号</returns>
		public ISAssetVersion CloneSelf() => Clone(this);
        
		/// <summary>
		/// 克隆
		/// </summary>
		/// <param name="iVersion">版本号</param>
		/// <returns>克隆版本</returns>
		public static ISAssetVersion Clone(ISAssetVersion iVersion)
		{
			if (null == iVersion || !iVersion.Valid) return null;
			var cloneVersion = Create();
			if (null == cloneVersion || !cloneVersion.Valid) return null;

			cloneVersion.ApplyData(iVersion);
			return cloneVersion;
		}

		/// <summary>
		/// 有效标志位
		/// </summary>
		public override bool Valid => 0 <= min && 0 <= mid && 0 <= max;

#region Equals

		public override int GetHashCode()
		{
			var nameTmp = GetType().FullName;
			if (string.IsNullOrEmpty(nameTmp))
			{
				nameTmp = GetType().Name;
			}
			return nameTmp.GetHashCode();
		}

		protected bool Equals(SAssetVersion iOther)
		{
			return min == iOther.min && mid == iOther.mid && max == iOther.max && 
			       !UtilsString.Diff(tag, iOther.tag);
		}

		public override bool Equals(object iObj)
		{
			if (ReferenceEquals(null, iObj)) return false;
			if (ReferenceEquals(this, iObj)) return true;
			return iObj.GetType() == GetType() && Equals((SAssetVersion) iObj);
		}

#endregion


#region Encode&Decode

		/// <summary>
		/// 编码
		/// </summary>
		/// <param name="iVersion">版本信息</param>
		/// <returns>版本信息(格式:0.0.0)</returns>
		public static string Encode(SAssetVersion iVersion)
		{
			return iVersion?.Full;
		}
		
		/// <summary>
		/// 编码
		/// </summary>
		/// <param name="iMax">版本信息 - 大</param>
		/// <param name="iMid">版本信息 - 中</param>
		/// <param name="iMin">版本信息 - 小</param>
		/// <param name="oVersion">版本信息</param>
		/// <param name="iTag">Tag</param>
		/// <returns>版本信息(格式:0.0.0.0.0)</returns>
		public static string Encode(Int16 iMax, Int16 iMid, Int16 iMin, out SAssetVersion oVersion, string iTag = null)
		{
			oVersion = new SAssetVersion
			{
				max = iMax, mid = iMid, min = iMin, tag = iTag
			};
			return oVersion?.ToString();
		}

		/// <summary>
		/// 解码
		/// </summary>
		/// <param name="iVersionDetail">版本详细信息(格式:0.0.0)</param>
		/// <param name="iTag">Tag</param>
		/// <returns>版本信息</returns>
		public static SAssetVersion Decode(string iVersionDetail, string iTag)
		{
			if (string.IsNullOrEmpty(iVersionDetail))
			{
				throw new InvalidSAssetVersionException("版本字符串为空!");
			}
			var values = iVersionDetail.Split('.');
			if (3 != values.Length)
			{
				throw new InvalidSAssetVersionException($"无效版本!({iVersionDetail})");
			}
			
			// 版本信息设定
			var version = Decode(iVersionDetail);

			if (!string.IsNullOrEmpty(iTag))
			{
				version.tag = iTag;
			}
			return version;
		}

		/// <summary>
		/// 解码
		/// </summary>
		/// <param name="iVersionDetail">版本详细信息(格式:0.0.0.0.0)</param>
		/// <returns>版本信息</returns>
		public static SAssetVersion Decode(string iVersionDetail)
		{
			if (string.IsNullOrEmpty(iVersionDetail)) 
			{
				throw new InvalidSAssetVersionException("版本字符串为空!");
			}
			var values = iVersionDetail.Split('.');
			if (3 != values.Length)
			{
				throw new InvalidSAssetVersionException($"无效版本!({iVersionDetail})");
			}

			// 版本信息设定
			var version = new SAssetVersion
			{
				max = Convert.ToInt16(values[0]),
				mid = Convert.ToInt16(values[1]),
				min = Convert.ToInt16(values[2])
			};

			if (4 <= values.Length)
			{
				version.tag = values[3];
			}
			return version;
		}

#endregion
        
#region Operator

		/// <summary>
		/// 运算符重载(==)
		/// </summary>
		/// <param name="iX">版本X</param>
		/// <param name="iY">版本Y</param>
		/// <returns>true:相等; false:不相等;</returns>
		public static bool operator ==(SAssetVersion iX, SAssetVersion iY)
		{
			switch (iX)
			{
				case null when ReferenceEquals(iY, null):
					return true;
				case null:
					return false;
			}

			if (ReferenceEquals(iY, null)) return false;

			return (iX.max == iY.max && iX.mid == iY.mid && iX.min == iY.min && 
			        !UtilsString.Diff(iX.Tag, iY.tag));
		}

		/// <summary>
		/// 运算符重载(!=)
		/// </summary>
		/// <param name="iX">版本X</param>
		/// <param name="iY">版本Y</param>
		/// <returns>true:不相等; false:相等;</returns>
		public static bool operator !=(SAssetVersion iX, SAssetVersion iY)
		{
			switch (iX)
			{
				case null when ReferenceEquals(iY, null):
					return false;
				case null:
					return true;
			}

			if (ReferenceEquals(iY, null)) return true;
			
			return (iX.max != iY.max || iX.mid != iY.mid || iX.min != iY.min || 
			        UtilsString.Diff(iX.Tag, iY.tag));
		}

		/// <summary>
		/// 运算符重载(<)
		/// </summary>
		/// <param name="iX">版本X</param>
		/// <param name="iY">版本Y</param>
		/// <returns>true:X小于Y; false:Y大于等于X;</returns>
		public static bool operator < (SAssetVersion iX, SAssetVersion iY)
		{
			if (null == iX && null == iY) return false;
			if (null == iX) return true;
			if (null == iY) return false;
			if (iX == iY) return false;

			// Max
			if (iX.max < iY.max)
			{
				return true;
			}

			// Mid
			if (iX.mid < iY.mid)
			{
				return true;
			}
			
			// Min
			if (iX.min < iY.min)
			{
				return true;
			}

			if (!UtilsString.Diff(iX.Tag, iY.Tag)) return false;
			return string.Compare(iX.Tag, iY.Tag, StringComparison.Ordinal) < 0;
		}
		
		/// <summary>
		/// 运算符重载(>)
		/// </summary>
		/// <param name="iX">版本X</param>
		/// <param name="iY">版本Y</param>
		/// <returns>true:X大于Y; false:X小于等于Y;</returns>
		public static bool operator > (SAssetVersion iX, SAssetVersion iY)
		{
			if (null == iX && null == iY) return false;
			if (null == iX) return false;
			if (null == iY) return true;
			if (iX == iY) return false;

			// Max
			if (iX.max > iY.max)
			{
				return true;
			}

			// Mid
			if (iX.mid > iY.mid)
			{
				return true;
			}
			
			// Min
			if (iX.min > iY.min)
			{
				return true;
			}
			
			if (!UtilsString.Diff(iX.Tag, iY.Tag)) return false;
			return string.Compare(iX.Tag, iY.Tag, StringComparison.Ordinal) > 0;
		}

		/// <summary>
		/// 运算符重载(<)
		/// </summary>
		/// <param name="iX">版本X</param>
		/// <param name="iY">版本Y</param>
		/// <returns>true:X小于Y; false:Y大于等于X;</returns>
		public static bool operator <=(SAssetVersion iX, SAssetVersion iY)
		{
			if (null == iX && null == iY) return true;
			if (null == iX) return true;
			if (null == iY) return false;
			if (iX == iY) return true;
			return iX < iY;
		}

		/// <summary>
		/// 运算符重载(>=)
		/// </summary>
		/// <param name="iX">版本X</param>
		/// <param name="iY">版本Y</param>
		/// <returns>true:X小于Y; false:Y大于等于X;</returns>
		public static bool operator >=(SAssetVersion iX, SAssetVersion iY)
		{
			if (null == iX && null == iY) return true;
			if (null == iX) return false;
			if (null == iY) return true;
			if (iX == iY) return true;
			return iX > iY;
		}

#endregion

		/// <summary>
		/// 应用数据
		/// </summary>
		/// <param name="iData">数据</param>
		/// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
		/// <returns>true:有变更; false:无变更;</returns>
		public override bool ApplyData(IJsonData iData, bool iImport = false)
		{
			if (null == iData || !iData.Valid) return false;

			var dirty = base.ApplyData(iData, iImport);
			if (dirty && !iImport)
			{
				Dirty = true;
			}

			if (iData is ISAssetVersion version)
			{
				tag = UpdateValue(tag, version.Tag, iImport);
				min = UpdateValue(min, version.Min, iImport);
				mid = UpdateValue(mid, version.Mid, iImport);
				max = UpdateValue(max, version.Max, iImport);
			}

			return Dirty;
		}

		/// <summary>
		/// 清空
		/// </summary>
		public override void Clear()
		{
			base.Clear();

			max = 0;
			mid = 0;
			min = 1;
			tag = null;
		}
	}
}
